package tools

import (
	"context"
	"encoding/json"
)

// Tool represents a tool that can be used by the AI
type Tool interface {
	// Name returns the name of the tool
	Name() string

	// Description returns a description of what the tool does
	Description() string

	// Parameters returns the parameters required by the tool
	Parameters() []Parameter

	// Execute executes the tool with the given parameters
	Execute(ctx context.Context, params map[string]interface{}) (interface{}, error)
}

// Parameter represents a parameter for a tool
type Parameter struct {
	Name        string      `json:"name"`
	Type        string      `json:"type"`              // string, number, boolean, array, object
	Description string      `json:"description"`       // description of the parameter
	Required    bool        `json:"required"`          // whether the parameter is required
	Default     interface{} `json:"default,omitempty"` // default value if not provided
}

// ToolResult represents the result of executing a tool
type ToolResult struct {
	Success bool        `json:"success"`
	Data    interface{} `json:"data,omitempty"`
	Error   string      `json:"error,omitempty"`
}

// ToolManager manages the available tools
type ToolManager struct {
	tools map[string]Tool
}

// NewToolManager creates a new tool manager
func NewToolManager() *ToolManager {
	return &ToolManager{
		tools: make(map[string]Tool),
	}
}

// RegisterTool registers a new tool
func (m *ToolManager) RegisterTool(tool Tool) {
	m.tools[tool.Name()] = tool
}

// GetTool gets a tool by name
func (m *ToolManager) GetTool(name string) Tool {
	return m.tools[name]
}

// ListTools lists all available tools
func (m *ToolManager) ListTools() []Tool {
	tools := make([]Tool, 0, len(m.tools))
	for _, tool := range m.tools {
		tools = append(tools, tool)
	}
	return tools
}

// ExecuteTool executes a tool by name
func (m *ToolManager) ExecuteTool(ctx context.Context, name string, params map[string]interface{}) (*ToolResult, error) {
	tool := m.GetTool(name)
	if tool == nil {
		return &ToolResult{
			Success: false,
			Error:   "tool not found",
		}, nil
	}

	result, err := tool.Execute(ctx, params)
	if err != nil {
		return &ToolResult{
			Success: false,
			Error:   err.Error(),
		}, nil
	}

	return &ToolResult{
		Success: true,
		Data:    result,
	}, nil
}

// GetToolSchema returns the JSON schema for a tool
func (m *ToolManager) GetToolSchema(name string) (string, error) {
	tool := m.GetTool(name)
	if tool == nil {
		return "", nil
	}

	schema := map[string]interface{}{
		"name":        tool.Name(),
		"description": tool.Description(),
		"parameters":  tool.Parameters(),
	}

	data, err := json.MarshalIndent(schema, "", "  ")
	if err != nil {
		return "", err
	}

	return string(data), nil
}
